/**
 * 
 */
package rmi;

import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;

/**
 * @author REMY Timothée and CARTIER Arthur
 */
public class User extends UnicastRemoteObject implements Remote, UserInterface {

	private static final long serialVersionUID = 870346772393468776L;

	/**
	 * @uml.property name="pseudo"
	 */
	private String pseudo;

	/**
	 * @uml.property name="ip"
	 */
	private String ip;

	/**
	 * @uml.property name="port"
	 */
	private int port = 1099;

	private Me me;

	public User() throws RemoteException {
		super();
		pseudo = "";
	}

	/**
	 * @param pseudo
	 * @param ip
	 * @param port
	 * @param me
	 * @throws RemoteException
	 */
	public User(final String pseudo, final String ip, final int port,
			final Me me) throws RemoteException {
		super();
		this.pseudo = pseudo;
		this.ip = ip;
		this.port = port;
		this.me = me;
	}

	/**
	 * @see rmi.UserInterface#disconnect() TODO Arthur refait ca et me cherche
	 *      un café.
	 */
	@Override
	public void disconnect(final String pseudo) {
		if (me.getFriends().containsKey(pseudo)) {
			me.getFriends().get(pseudo)._setConnected(false);
			try {
				me.getFriends().get(pseudo)._setDistantUser(null);
			} catch (final RemoteException e) {
				// this exception can't be launch when the parameter is null
			}
		}
	}

	/**
	 * @see rmi.UserInterface#equals(java.lang.Object)
	 * @param obj
	 * @return
	 */
	@Override
	public boolean equals(final Object obj) {
		if (this == obj) {
			return true;
		}
		if (!(obj instanceof UserInterface)) {
			return false;
		}
		final UserInterface other = (UserInterface) obj;
		if (pseudo == null) {
			try {
				if (other.getPseudo() != null) {
					return false;
				}
			} catch (final RemoteException e) {
				System.err
						.println("Equals : Error during acces to the remote pseudo value");
				e.printStackTrace();
			}
		} else {
			try {
				if (!pseudo.equals(other.getPseudo())) {
					return false;
				}
			} catch (final RemoteException e) {
				System.err
						.println("Equals : Error during acces to the remote pseudo value");
				e.printStackTrace();
			}
		}
		return true;
	}

	/**
	 * @see rmi.UserInterface#getIp()
	 * @return
	 */
	@Override
	public String getIp() {
		return ip;
	}

	/**
	 * @return the me
	 */
	protected Me getMe() {
		return me;
	}

	/**
	 * @see rmi.UserInterface#getPort()
	 * @return
	 */
	@Override
	public int getPort() {
		return port;
	}

	/**
	 * @see rmi.UserInterface#getPseudo()
	 * @return
	 */
	@Override
	public String getPseudo() {
		return pseudo;
	}

	/**
	 * @see rmi.UserInterface#initDiscussion(rmi.Discussion)
	 * @param newDiscussion
	 * @return
	 * @throws RemoteException
	 */
	@Override
	public boolean initDiscussion(final DiscussionInterface newDiscussion)
			throws RemoteException {
		if (!me.getCurrentDiscussions().contains(newDiscussion)) {
			// Automatic pick-up the discussion
			@SuppressWarnings("unchecked")
			final Discussion newLocalDiscussionObject = new Discussion(
					(ArrayList<UserInterface>) (newDiscussion)
							.getParticipants().clone(), newDiscussion.getId(),
					(ArrayList<DiscussionInterface>) newDiscussion
							.getListDiscussions().clone());

			newLocalDiscussionObject.getListDiscussions().add(newDiscussion);

			for (final DiscussionInterface remoteDiscussion : newLocalDiscussionObject
					.getListDiscussions()) {
				remoteDiscussion.join(newLocalDiscussionObject, me);
			}
			newLocalDiscussionObject.getParticipants().add(me);

			me.getCurrentDiscussions().add(newLocalDiscussionObject);

		}
		return true;
	}

	/**
	 * @see rmi.UserInterface#searchFriend(java.lang.String, int)
	 * @param pseudo
	 * @param ttl
	 * @return
	 * @throws RemoteException
	 */
	@Override
	public UserInterface searchFriend(final String pseudo, final int ttl)
			throws RemoteException {
		UserInterface result = null;
		if (me.getFriends().get(pseudo) != null
				&& me.getFriends().get(pseudo).isConnected()) {
			return me.getFriends().get(pseudo).getDistantUser();
		} else if (ttl > 0) {
			final int newttl = ttl - 1;
			for (final UserBuffer currentFriend : me.getFriends().values()) {
				if (currentFriend.isConnected()) {
					result = currentFriend.searchFriend(pseudo, newttl);

					if (result != null) {
						return result;
					}
				}
			}
		}
		return result;
	}

	/**
	 * Setter of the property <tt>ip</tt>
	 * 
	 * @param ip
	 *            The ip to set.
	 * @uml.property name="ip"
	 */
	public void setIp(final String ip) {
		this.ip = ip;
	}

	/**
	 * @param me
	 *            the me to set
	 */
	protected void setMe(final Me me) {
		this.me = me;
	}

	/**
	 * Setter of the property <tt>port</tt>
	 * 
	 * @param port
	 *            The port to set.
	 * @uml.property name="port"
	 */
	public void setPort(final int port) {
		this.port = port;
	}

	/**
	 * Setter of the property <tt>pseudo</tt>
	 * 
	 * @param pseudo
	 *            The pseudo to set.
	 * @uml.property name="pseudo"
	 */
	public void setPseudo(final String pseudo) {
		this.pseudo = pseudo;
	}

}
